#include "nmarrfield.h"
#include "util.h"
#include <string>
#include <cassert>
#include <vector>
#include <iostream>
#include <sstream>
#include <memory.h>

using namespace std;
using namespace opsrc::stdf;
const string listsep = "|";

template <typename T, int L, template <typename A, typename = std::allocator<A> > class CONT>
NmArrField<T,L,CONT>::NmArrField() {
}

template <typename T, int L, template <typename A, typename = std::allocator<A> > class CONT>
NmArrField<T,L,CONT>::NmArrField(char *buf, endian e, int elcount):en(e) {
	decode(buf, elcount);
}

template <typename T, int L, template <typename A, typename = std::allocator<A> > class CONT>
NmArrField<T,L,CONT>::~NmArrField() {
}

template <typename T, int L, template <typename A, typename = std::allocator<A> > class CONT >
int NmArrField<T,L,CONT>::getByteCount() const {
	return len;
}

template <typename T, int L, template <typename A, typename = std::allocator<A> > class CONT>
const CONT<T> NmArrField<T,L,CONT>::getData() const {
   return cont;
	
}

template <typename T, int L, template <typename A, typename = std::allocator<A> > class CONT>
int NmArrField<T,L,CONT>::getCount() const {
	return cont.size();
}

template <typename T, int L, template <typename A, typename = std::allocator<A> > class CONT>
void NmArrField<T,L,CONT>::decode(char* buf, int elemcount) {
	
	for ( int i=0; i < elemcount; i++ ) {

		char tmp[L];
		::memcpy(tmp, buf+(L*i), L);
		if (en == little_endian) {
	        Util::swapByteChar(&tmp[0], L);
		}
	    T d = Util::charToUnsignInt(&tmp[0], L);
	    	
    	// insert into container
    	cont.push_back(d);
	}
	
	len = L * elemcount;
}


template <typename T, int L, template <typename A, typename = std::allocator<A> > class CONT>
string NmArrField<T,L,CONT>::arrayToString() {
	string result;
	
	unsigned int i =0;
	typename CONT<T>::const_iterator iter;
	
	// build char delimiter string. For example: 1, 2, 3, 4
	for ( iter= cont.begin();  iter != cont.end(); i++, iter++ ) {
		
		std::ostringstream stm;
	    stm << *iter;		
		result += stm.str();
		if (i+1 != cont.size())	result += ",";  // append separator
	}	
	return result;	
}

template <typename T, int L, template <typename A, typename = std::allocator<A> > class CONT>
int NmArrField<T,L,CONT>::getTotalByteCount()  const {
   return len;	
}


// Specialization for float type, added by Jimmy @ 2010-04-09
// ******************************************************

template <int L, template <typename A, typename = std::allocator<A> > class CONT >
NmArrField<float,L,CONT>::NmArrField() {
}

template <int L, template <typename A, typename = std::allocator<A> > class CONT >
NmArrField<float,L,CONT>::NmArrField(char *buf, endian e, int elcount):en(e) {
	decode(buf, elcount);
}

template <int L, template <typename A, typename = std::allocator<A> > class CONT >
NmArrField<float,L,CONT>::~NmArrField() {
}

template <int L, template <typename A, typename = std::allocator<A> > class CONT >
int NmArrField<float,L,CONT>::getByteCount() const {
	return len;
}

template <int L, template <typename A, typename = std::allocator<A> > class CONT >
const CONT<float> NmArrField<float,L,CONT>::getData() const {
   return cont;
	
}

template <int L, template <typename A, typename = std::allocator<A> > class CONT >
int NmArrField<float,L,CONT>::getCount() const {
	return cont.size();
}

template <int L, template <typename A, typename = std::allocator<A> > class CONT >
void NmArrField<float,L,CONT>::decode(char* buf, int elemcount) {
	
	float d;

	for ( int i=0; i < elemcount; i++ ) {

		char tmp[L];
		::memcpy(tmp, buf+(L*i), L);
		if (en == little_endian) {
	      	  Util::swapByteChar(&tmp[0], L);
		}
	     
		d = Util::charToFloat(&tmp[0], L);

	    	// insert into container
	    	cont.push_back(d);
	}
	
	len = L * elemcount;
}

template <int L, template <typename A, typename = std::allocator<A> > class CONT >
string NmArrField<float,L,CONT>::arrayToString() {
	string result;
	
	unsigned int i =0;
	typename CONT<float>::const_iterator iter;
	
	// build char delimiter string. For example: 1, 2, 3, 4
	for ( iter= cont.begin();  iter != cont.end(); i++, iter++ ) {
		
		std::ostringstream stm;
	    	stm << *iter;		
		result += stm.str();
		if (i+1 != cont.size())	result += ",";  // append separator

	}	
	return result;	
}

template <int L, template <typename A, typename = std::allocator<A> > class CONT>
int NmArrField<float,L,CONT>::getTotalByteCount()  const {
   return len;	
}



// Specialization for bool type
// ******************************************************

template <int L, template <typename A, typename = std::allocator<A> > class CONT >
NmArrField<bool,L,CONT>::NmArrField() {
}

template <int L, template <typename A, typename = std::allocator<A> > class CONT >
NmArrField<bool,L,CONT>::NmArrField(char *buf, endian e, int elcount):en(e) {
	decode(buf, elcount);
}

template <int L, template <typename A, typename = std::allocator<A> > class CONT >
NmArrField<bool,L,CONT>::~NmArrField() {
}

template <int L, template <typename A, typename = std::allocator<A> > class CONT >
int NmArrField<bool,L,CONT>::getByteCount() const {
	return len;
}

template <int L, template <typename A, typename = std::allocator<A> > class CONT >
const CONT<bool> NmArrField<bool,L,CONT>::getData() const {
   return cont;
	
}

template <int L, template <typename A, typename = std::allocator<A> > class CONT >
int NmArrField<bool,L,CONT>::getCount() const {
	return cont.size();
}

template <int L, template <typename A, typename = std::allocator<A> > class CONT >
void NmArrField<bool,L,CONT>::decode(char* buf, int elemcount) {
	
	for ( int i=0; i < elemcount; i++ ) {

		char tmp[L];
		::memcpy(tmp, buf+(L*i), L);

		//updated by Jimmy change element 5 from 0x0f to 0x10
		int bit [] = { 0x01, 0x02, 0x04, 0x08, 0x10, 0x20, 0x40, 0x80};
		for ( int x=0; x < 8; x++ ) {
			bool val = ((tmp[i] & bit[x])== bit[x]);
		   	cont.push_back(val); 
		}
	}
	
	len = L * elemcount;
}


template <int L, template <typename A, typename = std::allocator<A> > class CONT >
string NmArrField<bool,L,CONT>::arrayToString() {
	string result;
	
	unsigned int i =0;
	typename CONT<bool>::const_iterator iter;
	
	// build char delimiter string. For example: 1, 2, 3, 4
	for ( iter= cont.begin();  iter != cont.end(); i++, iter++ ) {
		
		std::ostringstream stm;
	    stm << (*iter==true? "1": "0") ;		
		result += stm.str();
		if (i+1 != cont.size())	result += ",";  // append separator
	}	
	return result;	
}

//added by Jimmy to cater for vector of boolean type
template <int L, template <typename A, typename = std::allocator<A> > class CONT >
string NmArrField<bool,L,CONT>::at(int pos) {
	string result;
	
        int i =0;
	typename CONT<bool>::const_iterator iter;
	
	// build char delimiter string. For example: 1, 2, 3, 4
	for ( iter= cont.begin();  iter != cont.end(); i++, iter++ ) {
	
		if(i < pos)
			continue;
		else if(i > pos)
			break;

		std::ostringstream stm;
		stm << (*iter==true? "1": "0") ;		
		result += stm.str();
		//if (i+1 != cont.size())	result += ",";  // append separator
	}	

	return result;	
}


template <int L, template <typename A, typename = std::allocator<A> > class CONT>
int NmArrField<bool,L,CONT>::getTotalByteCount()  const {
   return len;	
}

// Specialization for Nibble type
// ******************************************************

template <int L, template <typename A, typename = std::allocator<A> > class CONT >
NmArrField<Nibble,L,CONT>::NmArrField() {
}

template <int L, template <typename A, typename = std::allocator<A> > class CONT >
NmArrField<Nibble,L,CONT>::NmArrField(char *buf, endian e, int elcount):en(e) {
	decode(buf, elcount);
}

template <int L, template <typename A, typename = std::allocator<A> > class CONT >
NmArrField<Nibble,L,CONT>::~NmArrField() {
}

template <int L,template <typename A, typename = std::allocator<A> > class CONT >
int NmArrField<Nibble,L,CONT>::getByteCount() const {
	return len;
}

template <int L, template <typename A, typename = std::allocator<A> > class CONT >
const CONT<int> NmArrField<Nibble,L,CONT>::getData() const {
   return cont;
	
}

template <int L, template <typename A, typename = std::allocator<A> > class CONT >
int NmArrField<Nibble,L,CONT>::getCount() const {
	return cont.size();
}

template <int L, template <typename A, typename = std::allocator<A> > class CONT >
void NmArrField<Nibble,L,CONT>::decode(char* buf, int elemcount) {
	
	char tmp[1];
	int m = 0 ; // offset for reading from buf

	for ( int i=0; i < elemcount; i++ ) {
		
		int result = 0; // initialized to zero

		// Read buffer
		if (i%2==0) {  // even i values
			::memcpy(tmp, buf + (m++), 1);
			
			// read lower 4 bits
			result = static_cast<int>(tmp[0] & 0x0f);
		}
		else {
			char b = tmp[0] >> 4;  // shift right
			result = static_cast<int>(b);
		}
		cont.push_back(result);
	}
	
	// According to STDF specs, odd number of Nibble type will be patch with zeros to found
	// a byte. Example, 3 nibble actually consist of 12 bits but actual storage is 16 bits 
	// or 2 bytes.
	len = (elemcount%2==0)? elemcount/2 : ((elemcount-1)/2) + 1 ;
}


template <int L, template <typename A, typename = std::allocator<A> > class CONT >
string NmArrField<Nibble,L,CONT>::arrayToString() {
	string result;
	
	unsigned int i =0;
	typename CONT<int>::const_iterator iter;
	
	// build char delimiter string. For example: 1, 2, 3, 4
	for ( iter= cont.begin();  iter != cont.end(); i++, iter++ ) {
		
		std::ostringstream stm;
	    stm << (*iter);	
		result += stm.str();
		if (i+1 != cont.size())	result += listsep;  // append separator
	}	
	return result;	
}

template <int L, template <typename A, typename = std::allocator<A> > class CONT>
int NmArrField<Nibble,L,CONT>::getTotalByteCount()  const {
   return len;	
}
